home *** CD-ROM | disk | FTP | other *** search
/ NetNews Offline 2 / NetNews Offline Volume 2.iso / news / comp / lang / c++-part2 / 17222 < prev    next >
Encoding:
Text File  |  1996-08-05  |  7.0 KB  |  216 lines

  1. Path: keats.ugrad.cs.ubc.ca!not-for-mail
  2. From: c2a192@ugrad.cs.ubc.ca (Kazimir Kylheku)
  3. Newsgroups: comp.lang.c,comp.lang.c++
  4. Subject: Re: sizeof() question >>> :)
  5. Date: 14 Apr 1996 09:00:12 -0700
  6. Organization: Computer Science, University of B.C., Vancouver, B.C., Canada
  7. Message-ID: <4kr7ecINN16d@keats.ugrad.cs.ubc.ca>
  8. References: <1996Apr12.061927@topaz>
  9. NNTP-Posting-Host: keats.ugrad.cs.ubc.ca
  10.  
  11. In article <1996Apr12.061927@topaz>,  <naderr@topaz.cqu.edu.au> wrote:
  12. >Hi,
  13. >
  14. >How can I get, with a pointer,  the sizeof  of an  array that is
  15. >pointed by the pointer ?  (No it's not a tounge twister :)
  16. >
  17. >Ok, let see if with an example I  could clarify what I'm trying to say,
  18. >
  19. >
  20. >  char First_name[20];
  21. >  char Last_name[20];
  22. >  char Address[60];
  23. >  char Phone[20];
  24. >  char **ct, *cp;
  25. >  char *record[4];
  26. >  char ch;
  27. >  
  28. >  record[0] = First_name;
  29. >  record[1] = Last_name;
  30. >  record[2] = Address;
  31. >  record[3] = Phone;
  32. >  ct = record;
  33. >  cp = *ct;
  34. >
  35. >  while (!done) {
  36. >    ch = getchar();
  37. >    if (cp - *ct < sizeof(XXXXXXX)-1) {
  38. >      *cp++ = ch;
  39. >    } else {
  40. >      beep();
  41. >    }  
  42. >  }
  43. >
  44. >for XXXXXXX the _only_ thing that I can find that works is to stick 
  45. >in there is the actual array that cp is pointing to, i.e. sizeof(First_name).
  46. >
  47. >What ideas do you have so that I can get the size of the array currently 
  48. >pointed to by cp?
  49.  
  50. You mean the remaining bytes in the object into which cp points? This is not
  51. possible. The type that cp points to is a single char, so sizeof *cp is the same
  52. thing as sizeof (char). sizeof First_Name works to give you the entire size
  53. because First_Name is an lvalue expression that names an array object.
  54.  
  55. Ignore the replies that mention strlen(), since this function is inapplicable
  56. to your problem at all. They are completely off mark (that's what you get for
  57. cross-posting what is essentially a C question to comp.lang.c++).
  58.  
  59. The string length (as defined by C Language and the strlen() standard defined
  60. function) of your arrays is either: 1) *zero* if they are *static*, since they
  61. will be initialized to contain all zero chars, or 2) *undefined* if they are
  62. automatic, since the contents are undefined, and may not necessarily include a
  63. zero character. The strlen() function cannot be used to determine the size of
  64. these character arrays.
  65.  
  66. Your real problem is that cp could point to the first element of any one of a
  67. number of different character arrays. The record[] array holds only the pointer
  68. to the first character of these arrays, not any size information.
  69.  
  70. May I suggest an alternative representation to the one you are using? You
  71. should really be using the C ``struct'' facility to represent records, not
  72. fields.
  73.  
  74. Place these declarations into a ``person.h'' header file. This can be included
  75. by any module which wants to access the person record.
  76.  
  77.  
  78.     typedef char firstnm_t[20];
  79.     typedef char lastnm_t[20];
  80.     typedef char address_t[60];
  81.     typedef char phoneno_t[20];
  82.  
  83.     typedef struct person {
  84.         firstnm_t First_Name;
  85.         lastnm_t Last_Name;
  86.         address_t Address;
  87.         phoneno_t Phone;
  88.     } person;
  89.  
  90.     
  91.     int read_person(struct person *P, FILE *f);
  92.  
  93. The reason I would use typedef names for the various fields is simple. Suppose
  94. that these persons are users, and later on I want to declare a structure which
  95. associates some data to users. I may want to use their phone number, say, as an
  96. identifier. Without the typedef name ``phoneno_t'', I will have to declare this
  97. separately as a 20-char array. Then later if I want to change the length of a
  98. phone number, I will have to hunt for all the places that use phone numbers
  99. instead of changing just one type.
  100.  
  101.     phoneno_t A, B;
  102.  
  103.     ...
  104.  
  105.     memcpy(B, A, sizeof(phoneno_t));
  106.  
  107. Some C programmers would rather not make a typedef name for the structure, and
  108. always refer to it with a qualified type expression ``struct person''. 
  109. The identifier following the ``struct'' keyword is a ``tag name'': union and
  110. struct tag names have their own space separate from other identifiers, so it's
  111. OK to have a ``person'' type name as well as a ``struct person'' structure.
  112.  
  113. In the implementation portion, ``person.c'', you define the function
  114. read_person(), as well as a function for reading character fields called
  115. ``readfield''. The fgets() function could also be used to implement readfield()
  116. with slightly different semantics. With fgets(), you could not quite as readily
  117. discriminate between input that just perfectly fits the field array size and
  118. one which is de facto too long, since fgets() does not look forward to the
  119. lookahead once it has read enough characters to satisfy the buffer size less
  120. one character.
  121.  
  122.     #include <stdio.h>
  123.     #include "person.h"
  124.  
  125.     int readfield(char *b, size_t s, FILE *f)
  126.  
  127.     {
  128.         char c;
  129.  
  130.         /* while there are two or more characters of space in buffer
  131.            b, and there is no EOF or end of line on reading f... */
  132.  
  133.         while(s > 1 && ((c = getc(f)) != EOF) && c != '\n') {
  134.             *b++ = c;    /* add the character        */
  135.             s--;        /* decrement avail. char count    */
  136.         }
  137.  
  138.         if (s > 0) {        /* if there is space    */
  139.             *b++ = '\0';    /* null terminate    */
  140.             s--;
  141.         }
  142.  
  143.         /* if EITHER the buffer is precisely filled and we have
  144.            not just seen a newline character (field is too long)
  145.            OR an EOF condition has been detected on the stream,
  146.            return failure */
  147.  
  148.         if (!s && c != '\n' || c == EOF)    
  149.             return 0;
  150.  
  151.         return 1;    /* otherwise success    */
  152.     }
  153.  
  154. /***
  155. *    
  156. *    The above function could be written, perhaps more succintly, as
  157. *
  158. *    #include <string.h>
  159. *
  160. *    int readfield(char *b, size_t s, FILE *f)
  161. *
  162. *    {
  163. *        char *nl;
  164. *
  165. *        if (!fgets(b, s, f))
  166. *            return 0;
  167. *
  168. *    The check here is that if no newline is found in the string obtained
  169. *     from fgets() (and there is at most one, thus strchr rather than
  170. *    strrchr is used) then the field is too long, UNLESS the next input
  171. *    character in f is a newline, which we readily gobble.
  172. *
  173. *        if (!(nl = strchr(b, '\n')))
  174. *            if (getc(f) != '\n')
  175. *                return 0;
  176. *        else
  177. *            *nl = '\0';
  178. *
  179. *    And of course, we must overwrite the newline with a zero, if and only
  180. *    if it WAS read in by fgets().
  181. *
  182. *        return 1;
  183. *    }
  184. *
  185. ***/
  186.  
  187.     int read_person(person *P, FILE *f)
  188.  
  189.     {
  190.         if(!readfield(P->First_Name, sizeof(firstnm_t), f))
  191.             return 0;
  192.         if(!readfield(P->Last_Name, sizeof(lastnm_t), f))
  193.             return 0;
  194.         if(!readfield(P->Address, sizeof(address_t), f))
  195.             return 0;
  196.         if(!readfield(P->Phone, sizeof(phoneno_t), f))
  197.             return 0;
  198.         return 1;
  199.     }
  200.  
  201. The read_person() function calls for a pointer to a person type and a stdio
  202. file pointer. It returns zero/false if it fails for some reason, at which
  203. point it would be advisable to check ferror(f) and feof(f). If neither of these
  204. are true, the reason for failure was that one of the input lines exceed the
  205. maximum length, causing truncation. If you don't care about this, you might
  206. want to change readfield() to just truncate without warning.
  207.  
  208. Caveats: Despite my usually better judgement, I have not tested the code before
  209. posting. So expect anything.  The readfield() function clearly does not belong
  210. with the ``person.c'' code. It should be by itself, or in a library module
  211. filled with related functions.
  212.  
  213. That's my detailed post of this week.
  214.  
  215. Cheers... Kaz
  216.